﻿using System;
using System.Collections;
using System.Text;
using System.IO;
using System.Data;
using System.Data.OleDb;
using System.Data.SqlClient;
using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.Zip.Compression;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;


namespace MyBook66
{
    public class MyBookInterface
    {
        #region 数据库连接
        /// <summary>
        /// 访问数据库用连接,一直打开
        /// </summary>
        private OleDbConnection dbo;
        /// <summary>
        /// MyBook66的数据库路径
        /// </summary>
        private string dbPath;
        /// <summary>
        /// 获取MyBook66数据库位置
        /// </summary>
        public string MyBook66DBPath
        {
            get
            {
                return dbPath;
            }
        }
        private string basePath;
        /// <summary>
        /// 获取数据库连接字串
        /// </summary>
        private string MyBook66ConnectionString
        {
            get
            {
                return string.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0}", dbPath);
            }
        }
        #endregion

        #region 书库结构
        private DataTable books;
        /// <summary>
        /// 获取书库结构
        /// </summary>
        public DataTable MyBook66Structure
        {
            get
            {
                return books ;
            }
        }
        /// <summary>
        /// 列出书籍章节列表
        /// </summary>
        /// <param name="bookID"></param>
        /// <returns></returns>
        public DataTable GetChapterList(string bookID)
        {
            return getData(string.Format(@"select id,title,bIsRead from book_novelContent where NovelID='{0}' order by displayorder asc",bookID));
        }
        /// <summary>
        /// 获取书籍结构
        /// </summary>
        private void populateBooks()
        {
            books = getData(@"
select tba.NovelID,tba.NovelName,tba.LB as GroupID,tbb.mc as GroupName,
        tba.Author,tba.ListUrl
from book_novel tba, dic_noveltype tbb
where tba.LB=tbb.DM
order by tba.lb");

        }
        public DataTable UnReadBooks
        {
            get
            {
                return getData(@"select tba.NovelID,tba.NovelName,tba.LB as GroupID,tbb.mc as GroupName,
        tba.Author,tba.ListUrl,tbc.cnt as UnRead
from book_novel tba, dic_noveltype tbb,(select count(id) as cnt,novelid from book_novelContent where bisread='0' group by novelid )tbc
where tba.LB=tbb.DM
  and tba.novelid=tbc.novelid
order by tba.lb");
            }
        }
        /// <summary>
        /// 标记已读
        /// </summary>
        /// <param name="bookID"></param>
        public void setRead(string bookID)
        {
            OleDbCommand cmd = dbo.CreateCommand();
            cmd.CommandText = String.Format(@"update book_novelContent set bIsRead='1' where novelid='{0}'", bookID);
            cmd.ExecuteNonQuery();
            cmd.Dispose();


        }
        public string getBookNameFromID(string bookID)
        {
            if (books != null)
            {
                DataRow[] dr = books.Select(string.Format("NovelID={0}",bookID));
                if (dr.Length != 0)
                {
                    return dr[0]["NovelName"].ToString();


                }else  return "errorNotFound";
            }
            else return "errorGettingData";
        }
        #endregion

        #region 获取内容
        /// <summary>
        /// 获取章节内容
        /// </summary>
        /// <param name="chapterID"></param>
        /// <returns></returns>
        public string getChapterContent(string chapterID,string bookID)
        {
            string res = "";
            string kk = string.Format("{0}\\chm\\{1}\\{2}.htm", new string[] { basePath, bookID, chapterID });
            if (File.Exists(kk))
            {
                res = File.ReadAllText(kk, Encoding.Default);
                return res;
            }
            else return "";
            
 
        }
        /// <summary>
        /// 获取FB2格式书籍内容
        /// </summary>
        /// <param name="bookID">书籍ID</param>
        /// <returns></returns>
      
        /// <summary>
        /// 缓存章节列表
        /// </summary>
        private Hashtable cachedList;
        /// <summary>
        /// 缓存书籍列表所对应的章节列表
        /// </summary>
        private string cachedBookID;
        private bool isCached = false;
        /// <summary>
        /// 是否已经缓冲过
        /// </summary>
        public bool IsCached
        {
            get
            {
                return isCached;
            }
        }
        /// <summary>
        /// 读写CachedBookID
        /// </summary>
        public string CachedBookID
        {
            get
            {
                return cachedBookID;
            }
            set
            {
            	cachedBookID = value;
                //cache the book
                try
                {

                    using (DataTable dt = getData(string.Format(@"SELECT id,title
FROM book_NovelContent
where novelid = '{0}'
order by displayorder asc", value)))
                    {
                        isCached = true;

                        cachedList = new Hashtable();

                        foreach (DataRow item in dt.Rows)
                        {
                            cachedList.Add(item["id"].ToString(), item["title"].ToString());
                        }
                    }

                }
                catch (Exception ex)
                {
                    Exception ee = new Exception(string.Format("缓冲书籍{0}的目录失败,详情:{1}",value,ex.Message));
                    isCached = false;
                    throw (ee);
                }
            }
        }
        /// <summary>
        /// 获取对应章节的物理位置
        /// </summary>
        /// <param name="chapterID">章节ID</param>
        /// <returns></returns>
        public string getChapterPath(string chapterID,string bookID)
        {
            if (String.Compare(bookID, this.CachedBookID, false) != 0)
            {
                this.CachedBookID = bookID;
            }
            if (cachedList.ContainsKey(chapterID))
            {
                string kk =  string.Format("{0}\\chm\\{1}\\{2}.htm",new string[]
                {basePath,bookID,chapterID});
                return File.Exists(kk) ? kk : "";
            }
            else
            {
                return "";
            }
           
        }
        public string getChapterTitle(string chapterID, string bookID)
        {
            if (String.Compare(bookID, this.CachedBookID, false) != 0) this.CachedBookID = bookID;
            return cachedList.ContainsKey(chapterID) ? (string)cachedList[chapterID] : "";
        }
        /// <summary>
        /// 获取书籍地址
        /// </summary>
        /// <param name="bookID"></param>
        /// <returns></returns>
        public string getBookPath(string bookID)
        {
            return string.Format("{1}\\chm\\{0}\\", bookID,basePath);
        }


        #endregion

        #region FB2/FBZ


        public MemoryStream getBookFB2(string bookID)
        {
            #region 获取书籍信息->bookTitle,bookAuthor,bookUrl;

            string bookTitle, bookAuthor, bookUrl;

            DataRow[] bookinfo = books.Select(string.Format("NovelID = {0}", bookID));
            if (bookinfo.GetLength(0) != 0)
            {
                bookTitle = bookinfo[0]["NovelName"].ToString();
                bookAuthor = bookinfo[0]["Author"].ToString();
                bookUrl = bookinfo[0]["ListUrl"].ToString();

            }
            else
            {
                throw (new Exception(string.Format("无法找到NovelID {0} ", bookID)));
            }

            #endregion

            #region 获取章节列表->bookChapters
            DataTable bookChapetrs = getData(string.Format(@"
select id,title,downdate,downtime,comefrom,Volume,wordnums
FROM book_NovelContent
where novelid = '{0}'
order by displayorder asc
            ", bookID));
            #endregion

            #region 获取所有章节的内容并整理为fb2 Section -> fbSections
            string fn, scache;
            string lastVolume = "";
            ArrayList fbSections = new ArrayList();

            foreach (DataRow d in bookChapetrs.Rows)
            {
                fn = string.Format("{0}\\chm\\{1}\\{2}.htm", new string[] { basePath, bookID, d["id"].ToString() });
                if (String.Compare(lastVolume, "", false) == 0)
                {
                    lastVolume = String.Compare(d["Volume"].ToString(), "", false) != 0 ? d["Volume"].ToString() : "正文";

                    fbSections.Add(toUTF8(string.Format("<section><title><p>{0}</p></title>", lastVolume)));

                }
                else
                    if (String.Compare(d["Volume"].ToString(), lastVolume, false) != 0 && (d["Volume"].ToString().Trim() != ""))
                    {
                        lastVolume = d["Volume"].ToString();
                        fbSections.Add(toUTF8(string.Format("</section><section><title><p>{0}</p></title>", lastVolume)));
                    }
                scache = getChapterContent(d["id"].ToString(), bookID);
                if (scache.Contains("<!--BookContent Start-->"))
                {
                    scache = scache.Substring(
                    scache.IndexOf("<!--BookContent Start-->") + 24,
                    scache.IndexOf("<!--BookContent End-->") - (scache.IndexOf("<!--BookContent Start-->") + 24));
                    scache = scache.Replace("&nbsp;", "").Replace("<br>", "</p><p>").Replace("</br>", "</p><p>").Replace("<br/>", "</p><p>").Replace("</ br>", "</p><p>").Replace("<br />", "</p><p>");

                }
                fbSections.Add(toUTF8(string.Format("<section><title><p>{0}</p></title><p>字数:{2}</p><p>{1}</p></section>", d["Title"].ToString(), scache, d["WordNums"].ToString())));
            }
            fbSections.Add(toUTF8("</section><section>"));
            #endregion

            #region 合并为MemoryStream

            MemoryStream sm = new MemoryStream();
            StreamWriter sw = new StreamWriter(sm, Encoding.UTF8);
            #region 初始化文件头

            sw.WriteLine("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
            sw.WriteLine("<FictionBook xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns=\"http://www.gribuser.ru/xml/fictionbook/2.0\">");
            sw.WriteLine("<description><title-info><genre match = \"0\">ChineseNetNovels</genre>");
            sw.WriteLine("<author><first-name>MyBook66 Downloaded</first-name><last-name>Almost All Piracy....</last-name></author>");
            sw.WriteLine(String.Format("<book-title>{0}</book-title>", bookTitle));
            sw.WriteLine(String.Format("<date value =\"{0}\">{1}</date>", DateTime.Today, DateTime.Today.Year));
            sw.WriteLine("<lang>ZH_CN</lang></title-info>");
            sw.WriteLine(string.Format("<document-info><author><nickname>{0}</nickname></author>", bookAuthor));
            sw.WriteLine("<program-used>MyBook66_To_FB2</program-used></document-info></description>");

            sw.WriteLine(String.Format("<body><title><p>{0}</p></title>", bookTitle));
            #endregion
            sw.WriteLine(string.Format(@"
<p>书籍作者:{0}</p>
<p>书籍制作于:{1}</p>
<p>书籍制作者:{2}</p>
<p>书籍制作工具:{3}</p>
<p>书籍数据来源于:{4}</p>
<p>原始数据来源于:{5}</p>
", new string[]
                {bookAuthor,
                 DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"),
                 "Sunfish",
                 "MyBook66 FB2 Exporter",
                 "华之城 小说下载阅读器",
                  bookUrl
                }));
            for (int i = 0; i < fbSections.Count; i++)
            {
                sw.WriteLine((string)fbSections[i]);
            }
            sw.WriteLine("</body></FictionBook>");

            #endregion
            sw.Flush();

            return sm;
        }
        public MemoryStream getBookFBZ(string bookID)
        {
            MemoryStream msm = new MemoryStream();
            MemoryStream mf = getBookFB2(bookID);
            ZipOutputStream stm = new ZipOutputStream(msm);
            stm.IsStreamOwner = false;
            stm.SetLevel(9);
            byte[] buf = mf.GetBuffer();
            ZipEntry et = new ZipEntry(string.Format("{0}.fb2",getBookNameFromID(bookID))) { DateTime = DateTime.Now, Size = buf.Length };
            stm.PutNextEntry(et);
            stm.Write(buf, 0, buf.Length);
            stm.Finish();
            stm.Close();
            return msm;
        }
        

        #endregion

        #region ePub
        /// <summary>
        /// return ePub in Memory Stream
        /// </summary>
        /// <param name="bookID"></param>
        /// <returns></returns>
        public MemoryStream getBook_ePub(string bookID)
        {
            //todo: epub.add minetype
             
            //todo: epub.add meta-inf

            //todo: epub.add content.opf

            //todo: epub.add cover pic

            //todo: epub.add toc

            //todo: epub.add other chapters


            return null;
        }
        /// <summary>
        /// minetype file
        /// </summary>
        private MemoryStream get_ePub_mimetype
        {
            get
            {
                MemoryStream MSM = new MemoryStream();
                StreamWriter sw = new StreamWriter(MSM);
                sw.WriteLine("application/epub+zip");
                sw.Flush();
                sw.Close();
                return MSM;
            }
        }
        /// <summary>
        /// meta-inf file
        /// </summary>
        private MemoryStream get_ePub_META_INF
        {
            get
            {
                MemoryStream MSM = new MemoryStream();
                StreamWriter sw = new StreamWriter(MSM);
                sw.WriteLine("<?xml version='1.0' encoding='utf-8'?>");
                sw.WriteLine("<container xmlns=\"urn:oasis:names:tc:opendocument:xmlns:container\" version=\"1.0\">");
                sw.WriteLine("<rootfiles>");
                sw.WriteLine("<rootfile full-path=\"OEBPS/content.opf\" media-type=\"application/oebps-package+xml\" />");
                sw.WriteLine("</rootfiles>");
                sw.WriteLine("</container>");
                sw.Flush();
                sw.Close();
                return MSM;

            }
        
        }
        /// <summary>
        /// todo:generate opf file
        /// </summary>
        private MemoryStream get_ePub_Content_OPF
        {
            get
            {
                return null;
            }
        }
        #endregion

        #region 辅助函数
        private DataTable getData(string sSQL)
        {
            DataTable dt = new DataTable();
            using (OleDbDataAdapter  oda = new OleDbDataAdapter(sSQL,dbo))
            {
                oda.Fill(dt);
            }
            return dt;
        }
        public static string toUTF8( string inStr)
        {
            return inStr;
            
           //return Encoding.UTF8.GetString(Encoding.Default.GetBytes(inStr));
        }
        #endregion

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="DBPath">pim.mdb存在位置</param>
        public MyBookInterface(string DBPath)
        {
            if (File.Exists(DBPath))
            {
                dbPath = DBPath;
                dbo = new OleDbConnection(MyBook66ConnectionString);
                try
                {
                    basePath = Path.GetDirectoryName(dbPath);
                    dbo.Open();

                    populateBooks();
                }
                catch (Exception ex)
                {
                    throw (ex);
                }
            }
            else
            {
                FileNotFoundException e = new FileNotFoundException(string.Format("文件{0}无法找到",DBPath));
                throw (e);
            }
        }
        
    }
}
